﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using WebApiClient;
using Zhj.Common.HystrixCore;
using AspectCore.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using Zhj.Somethings.OrderService.Service;

namespace Zhj.Somethings.OrderService
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
            //services.AddSingleton<OrderServiceImpl, Service.OrderService>(services);

            RegisterServices(services);
            RegisterServices(this.GetType().Assembly, services);
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            return services.BuildAspectCoreServiceProvider();
        }
        

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }


            app.UseMvc();

            string ip = Configuration["ip"];
            string port = Configuration["port"];
            string serviceName = "OrderService";
            string serviceId = serviceName + Guid.NewGuid();//唯一  服务编号，不能重复，用 Guid 最简单 
            //注册服务到 Consul 
            using (var consulClient = new ConsulClient(consulConfig))
            {
                AgentServiceRegistration asr = new AgentServiceRegistration();
                asr.Address = ip;   //服务提供者的能被消费者访问的 ip 地址(可以被其他应用访问的 地址，本地测试可以用 127.0.0.1，机房环境中一定要写自己的内网 ip 地址) 
                asr.Port = Convert.ToInt32(port);   // 服务提供者的能被消费者访问的端口 
                asr.ID = serviceId;  // 服务编号，不能重复，用 Guid 最简单
                asr.Name = serviceName;  //服务的名字 
                asr.Check = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),  //服务停止多久 后反注册(注销) 
                    HTTP = $"http://{ip}:{port}/api/Health", //健康检查地址 
                    Interval = TimeSpan.FromSeconds(10),  // //健康检查时间间隔，或者称为心跳间隔
                    Timeout = TimeSpan.FromSeconds(5)
                };
                consulClient.Agent.ServiceRegister(asr).Wait();
                //Consult 客户端的所有方法几乎都是异步方法，但是都没按照规范加上 Async 后缀，所以容易误导。记得调用后要 Wait()或者 await
            };
            //using (var consulClient = new ConsulClient(c=> { c.Address = new Uri("http://127.0.0.1:8500");c.Datacenter = "dc1"; }))

            //程序正常退出的时候从 Consul 注销服务  
            //要通过方法参数注入 IApplicationLifetime 
            appLifetime.ApplicationStopped.Register(() =>
            {
                using (var consulClient = new ConsulClient(consulConfig))
                {
                    Console.WriteLine("应用退出，开始从consul注销");
                    consulClient.Agent.ServiceDeregister(serviceId).Wait();
                }
            });

        }
        private static void RegisterServices(Assembly asm, IServiceCollection services)
        {
            //遍历程序集中的所有public类型
            foreach (Type type in asm.GetExportedTypes())
            {
                //判断类中是否有标注了CustomInterceptorAttribute的方法
                bool hasHystrixAttr = type.GetMethods()
                  .Any(m => m.GetCustomAttribute(typeof(HystrixCommandAttribute)) != null);
                if (hasHystrixAttr)
                {
                    services.AddSingleton(type);
                    Console.WriteLine("注册了一个" + type.ToString());
                }


            }
        }

        private static void RegisterServices(IServiceCollection services)
        {
            services.AddTransient<Service.OrderService, OrderServiceImpl>();
        }

        private void consulConfig(ConsulClientConfiguration c)
        {
            c.Address = new Uri("http://127.0.0.1:8500");
            c.Datacenter = "dc1";
        }
    }
}
